from PyQt5.QtWidgets import QWidget, QLabel, QGridLayout, QApplication, \
    QStackedWidget, QPushButton, QHBoxLayout, QVBoxLayout, QScrollArea, \
    QLineEdit, QFileDialog, QGraphicsDropShadowEffect, QDateTimeEdit, \
    QInputDialog
from PyQt5.QtGui import QPixmap, QFont, QIntValidator, QDoubleValidator, QCursor
from PyQt5.QtCore import Qt, pyqtSignal, QDate
from Dialog import FileDialog, WarningMessageBox, LoadingDialog
from base64 import b64encode, b64decode
import requests
import sys
import copy
import cv2
import numpy as np
from abc import ABCMeta, abstractmethod
from PyQt5.QtCore import QObject, QUrl, QByteArray
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest

activityList = [{
        "activity_id": "1",
        "activity_title": "全民种动园",  # 标题
        "activity_count": 50,  # 预设参加人数
        "status": 0,  # 状态
        "imagesSlider": [
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3205314663,2167162864&fm=26&gp=0.jpg",
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3992045535,69144840&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3156874013,635811390&fm=26&gp=0.jpg"
        ],   # 轮播图
        "defaultImgIndex": 0,  # 默认图片索引（取轮播图）
        "activity_signed": 12,  # 已参加人数
        "price": 59,  # 价格
        "activity_unit": "元/人",  # 单位
        "activity_start_date": "2020-07-20",  # 活动开始时间
        "activity_end_date": "2020-08-20",  # 活动结束时间
        "sign_start_date": "2020-07-13",  # 报名开始时间
        "sign_end_date": "2020-07-28",  # 报名结束时间
        "service_tel":"0721-8392580",   # 咨询电话
        "address": "测试",  # 地址
        "activity_content": "虽然做了一件好事，但很有可能因此招来他人的无端猜测，例如被质疑是否藏有其他利己动机等，乃至谴责。即便如此，还是要做好事。",#介绍
        "imageContent":[
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1887942828,972848009&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1956320807,1368482897&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2192842524,640789728&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2167237248,612060343&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1925142767,3806138753&fm=26&gp=0.jpg",
        ],  # 图片详情
    },
{
        "activity_id": "1",
        "activity_title": "全民种动园",  # 标题
        "activity_count": 50,  # 预设参加人数
        "status": 0,  # 状态
        "imagesSlider": [
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3205314663,2167162864&fm=26&gp=0.jpg",
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3992045535,69144840&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3156874013,635811390&fm=26&gp=0.jpg"
        ],   # 轮播图
        "defaultImgIndex": 1,  # 默认图片索引（取轮播图）
        "activity_signed": 12,  # 已参加人数
        "price": 59,  # 价格
        "activity_unit": "元/人",  # 单位
        "activity_start_date": "2020-07-20",  # 活动开始时间
        "activity_end_date": "2020-08-20",  # 活动结束时间
        "sign_start_date": "2020-07-13",  # 报名开始时间
        "sign_end_date": "2020-07-28",  # 报名结束时间
        "service_tel":"0721-8392580",   # 咨询电话
        "address": "测试",  # 地址
        "activity_content": "虽然做了一件好事，但很有可能因此招来他人的无端猜测，例如被质疑是否藏有其他利己动机等，乃至谴责。即便如此，还是要做好事。",#介绍
        "imageContent":[
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1887942828,972848009&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1956320807,1368482897&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2192842524,640789728&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2167237248,612060343&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1925142767,3806138753&fm=26&gp=0.jpg",
        ],  # 图片详情
    },
{
        "activity_id": "1",
        "activity_title": "全民种动园",  # 标题
        "activity_count": 50,  # 预设参加人数
        "status": 0,  # 状态
        "imagesSlider": [
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3205314663,2167162864&fm=26&gp=0.jpg",
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3992045535,69144840&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3156874013,635811390&fm=26&gp=0.jpg"
        ],   # 轮播图
        "defaultImgIndex": 2,  # 默认图片索引（取轮播图）
        "activity_signed": 12,  # 已参加人数
        "price": 59,  # 价格
        "activity_unit": "元/人",  # 单位
        "activity_start_date": "2020-07-20",  # 活动开始时间
        "activity_end_date": "2020-08-20",  # 活动结束时间
        "sign_start_date": "2020-07-13",  # 报名开始时间
        "sign_end_date": "2020-07-28",  # 报名结束时间
        "service_tel":"0721-8392580",   # 咨询电话
        "address": "测试",  # 地址
        "activity_content": "虽然做了一件好事，但很有可能因此招来他人的无端猜测，例如被质疑是否藏有其他利己动机等，乃至谴责。即便如此，还是要做好事。",#介绍
        "imageContent":[
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1887942828,972848009&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1956320807,1368482897&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2192842524,640789728&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2167237248,612060343&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1925142767,3806138753&fm=26&gp=0.jpg",
        ],  # 图片详情
    },
{
        "activity_id": "1",
        "activity_title": "全民种动园",  # 标题
        "activity_count": 50,  # 预设参加人数
        "status": 0,  # 状态
        "imagesSlider": [
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3205314663,2167162864&fm=26&gp=0.jpg",
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3992045535,69144840&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3156874013,635811390&fm=26&gp=0.jpg"
        ],   # 轮播图
        "defaultImgIndex": 0,  # 默认图片索引（取轮播图）
        "activity_signed": 12,  # 已参加人数
        "price": 59,  # 价格
        "activity_unit": "元/人",  # 单位
        "activity_start_date": "2020-07-20",  # 活动开始时间
        "activity_end_date": "2020-08-20",  # 活动结束时间
        "sign_start_date": "2020-07-13",  # 报名开始时间
        "sign_end_date": "2020-07-28",  # 报名结束时间
        "service_tel":"0721-8392580",   # 咨询电话
        "address": "测试",  # 地址
        "activity_content": "虽然做了一件好事，但很有可能因此招来他人的无端猜测，例如被质疑是否藏有其他利己动机等，乃至谴责。即便如此，还是要做好事。",#介绍
        "imageContent":[
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1887942828,972848009&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1956320807,1368482897&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2192842524,640789728&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2167237248,612060343&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1925142767,3806138753&fm=26&gp=0.jpg",
        ],  # 图片详情
    },
{
        "activity_id": "1",
        "activity_title": "全民种动园",  # 标题
        "activity_count": 50,  # 预设参加人数
        "status": 0,  # 状态
        "imagesSlider": [
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3205314663,2167162864&fm=26&gp=0.jpg",
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3992045535,69144840&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3156874013,635811390&fm=26&gp=0.jpg"
        ],   # 轮播图
        "defaultImgIndex": 1,  # 默认图片索引（取轮播图）
        "activity_signed": 12,  # 已参加人数
        "price": 59,  # 价格
        "activity_unit": "元/人",  # 单位
        "activity_start_date": "2020-07-20",  # 活动开始时间
        "activity_end_date": "2020-08-20",  # 活动结束时间
        "sign_start_date": "2020-07-13",  # 报名开始时间
        "sign_end_date": "2020-07-28",  # 报名结束时间
        "service_tel":"0721-8392580",   # 咨询电话
        "address": "测试",  # 地址
        "activity_content": "虽然做了一件好事，但很有可能因此招来他人的无端猜测，例如被质疑是否藏有其他利己动机等，乃至谴责。即便如此，还是要做好事。",#介绍
        "imageContent":[
            "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1887942828,972848009&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1956320807,1368482897&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2192842524,640789728&fm=26&gp=0.jpg",
            "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2167237248,612060343&fm=26&gp=0.jpg",
            "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1925142767,3806138753&fm=26&gp=0.jpg",
        ],  # 图片详情
    },

]

initActivityItemData = {
        "activity_id": "1",
        "activity_title": "",  # 标题
        "activity_count": 0,  # 预设参加人数
        "status": 0,  # 状态
        "imagesSlider": [
            "请点击插入图片",
            "请点击插入图片",
            "请点击插入图片"
        ],   # 轮播图
        "defaultImgIndex": 0,  # 默认图片索引（取轮播图）
        "activity_signed": 0,  # 已参加人数
        "price": 0,  # 价格
        "activity_unit": "元/人",  # 单位
        "activity_start_date": "2020-07-20",  # 活动开始时间
        "activity_end_date": "2020-08-20",  # 活动结束时间
        "sign_start_date": "2020-07-13",  # 报名开始时间
        "sign_end_date": "2020-07-28",  # 报名结束时间
        "service_tel":"0721-8392580",   # 咨询电话
        "address": "测试",  # 地址
        "activity_content": "虽然做了一件好事，但很有可能因此招来他人的无端猜测，例如被质疑是否藏有其他利己动机等，乃至谴责。即便如此，还是要做好事。",#介绍
        "imageContent":[
            "请点击插入图片",
            "请点击插入图片",
            "请点击插入图片",
            "请点击插入图片",
            "请点击插入图片",
        ],  # 图片详情
    }

class shopItem(QWidget):
    __metaclass__ = ABCMeta
    shopItemClicked = pyqtSignal(dict)

    def __init__(self, labelcount=2, displaytype=0, labelalign=Qt.AlignCenter, pic_label_space=6, parent=None):
        super(shopItem, self).__init__(parent)
        self._dataIndex = None
        # 布局
        self._layout1 = QGridLayout()
        self._layout2 = QGridLayout()
        self._layout1.setContentsMargins(0, 0, 0, 0)

        # 存放显示的数据
        self._data = None

        # label的数量
        self._labelCount = labelcount

        # 显示的方式0：图片在上 1：图片在左
        self._displayType = displaytype

        self._labelAlign = labelalign

        self._labelWidget = QWidget()
        self._labelWidget.setStyleSheet("background-color:white")
        # 显示图片
        self._picLb = QLabel()
        font = QFont()
        font.setPixelSize(30)
        font.setFamily("SimSun")
        self._picLb.setStyleSheet("background-color:gray")
        self._picLb.setFont(font)
        self._picLb.setAlignment(Qt.AlignCenter)

        self._descLbList = list()
        for index in range(self._labelCount):
            self._descLbList.append(QLabel())

        self._initLayout(pic_label_space)
        #self.setWindowFlags(Qt.FramelessWindowHint)

        self.m_netAccessManager = QNetworkAccessManager(self)
        self.m_netReply = None

    def q_request(self, url):
        if url.startswith("http"):
            if self.m_netReply is not None:
                self.m_netReply.disconnect()

            req = QNetworkRequest(QUrl(url))
            self.m_netReply = self.m_netAccessManager.get(req)

            self.m_netReply.finished.connect(self.readData)

        else:
            self._displayimg(url, self._picLb)

    def readData(self):
        recvData = self.m_netReply.readAll()
        pix = QPixmap()
        pix.loadFromData(recvData)
        pix = pix.scaled(self._picLb.width(), self._picLb.height())
        self._picLb.setPixmap(pix)
        image_byte = b64encode(recvData)
        base64_string = image_byte.decode('utf-8')
        self._data["imagesSlider"][0] = base64_string

    def _setPicSize(self, size):
        self._picLb.setFixedSize(size[0], size[1])

    def _initLayout(self, space):
        for each in range(self._descLbList.__len__()):
            self._layout2.addWidget(self._descLbList[each], each, 0, 1, 2, self._labelAlign)
            self._layout2.setContentsMargins(0, 0, 0, 0)
            self._labelWidget.setLayout(self._layout2)
        if self._displayType == 0:  # 上
            self._layout1.addWidget(self._picLb, 0, 0)
            self._layout1.addWidget(self._labelWidget, 1, 0)
        elif self._displayType == 1:  # 下
            self._layout1.addWidget(self._picLb, 0, 0)
            self._layout1.addWidget(self._labelWidget, 0, 1)
        elif self._displayType == 2:  # 左
            self._layout1.addWidget(self._picLb, 1, 0)
            self._layout1.addWidget(self._labelWidget, 0, 0)
        else:                        # 右
            self._layout1.addWidget(self._picLb, 0, 1)
            self._layout1.addWidget(self._labelWidget, 0, 0)
        self._layout1.setSpacing(space)
        self.setLayout(self._layout1)

    def _displayImg(self, url, label):
        pix = QPixmap()
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        if url.startswith("http"):
            QApplication.processEvents()
            response = requests.get(url)
            pix.loadFromData(response.content)
            pix = pix.scaled(label.width(), label.height())
            label.setStyleSheet("border:none")
            label.setPixmap(pix)
            image_byte = b64encode(response.content)
            base64_string = image_byte.decode('utf-8')
            QApplication.restoreOverrideCursor()
            return base64_string
        elif url == "请点击插入图片":
            label.setText(url)
            label.setStyleSheet("background-color:gray;border: 1px solid black;")
        else:
            url = url.encode("utf-8")
            image_data = b64decode(url)
            pix.loadFromData(image_data)
            pix = pix.scaled(label.width(), label.height())
            label.setStyleSheet("border:none")
            label.setPixmap(pix)
        QApplication.restoreOverrideCursor()
        return None

    def _setLabelSpacing(self, space):
        self._layout2.setSpacing(space)

    def getData(self):
        return self._data

    @abstractmethod
    def updateData(self, data):
        self._data = data
        pass

    def mouseReleaseEvent(self, event):
        super(shopItem, self).mouseReleaseEvent(event)
        if self._data is not None:
            self.shopItemClicked.emit(self._data)

    @abstractmethod
    def getSize(self):
        pass

    def setDataIndex(self, index):
        self._dataIndex = index

    def dataIndex(self):
        return self._dataIndex

# 轮播图切换按钮
class slideButton(QPushButton):
    # 通知当前显示的图片索引
    currentIndex = pyqtSignal(int)

    def __init__(self, index, parent=None):
        super(slideButton, self).__init__(parent)
        self._index = index
        self.clicked.connect(self._currentIndex)
        self.setCheckable(True)
        if index == 0:
            self.setChecked(True)
        self.setAutoExclusive(True)
        self.setStyleSheet("QPushButton{border: none;background-color: #00FFFF;} \
                                QPushButton:checked{background-color: rgb(48, 141, 162);}")

    def _currentIndex(self):
        self.currentIndex.emit(self._index)

    def index(self):
        return self._index

# 用于可编辑页面的图片显示
class picEditableLabel(QLabel):
    picLbClicked = pyqtSignal(int)

    def __init__(self, index=None, parent=None):
        super(picEditableLabel, self).__init__(parent)
        self._index = index
        font = QFont()
        font.setPixelSize(30)
        font.setFamily("SimSun")
        self.setFont(font)
        self.setAlignment(Qt.AlignCenter)

    def mouseReleaseEvent(self, event):
        super(picEditableLabel, self).mouseReleaseEvent(event)
        if self._index is None:
            self.picLbClicked.emit(-1)
        else:
            self.picLbClicked.emit(self._index)

    def index(self):
        return self._index

class activityItem(shopItem):
    def __init__(self):
        super(activityItem, self).__init__(labelcount=5, displaytype=1)
        # self.setFixedSize(250, 300)
        # self._setPicSize((250, 200))
        # self._setLabelSpacing(0)
        # self.setFixedSize(300, 100)
        # self._setPicSize((100, 100))
        self.setFixedSize(500, 300)
        self._setPicSize((300, 300))
        sd = QGraphicsDropShadowEffect()
        sd.setColor(Qt.gray)
        sd.setBlurRadius(8)
        self.setGraphicsEffect(sd)

    def updateData(self, data):
        self._data = data
        # 显示图片
        url = data["imagesSlider"][data["defaultImgIndex"]]
        self._displayImg(url, self._picLb)

        # 显示标题
        font = QFont()
        font.setBold(True)
        font.setPixelSize(14)
        font.setFamily("黑体")
        self._descLbList[0].setFont(font)
        self._descLbList[0].setText(data["activity_title"])

        # 显示价格
        self._descLbList[1].setStyleSheet("color: red")
        font.setPixelSize(20)
        self._descLbList[1].setFont(font)
        self._descLbList[1].setText("¥" + str(data["price"]))

        # 显示活动开始和结束时间
        font.setPixelSize(13)
        font.setBold(False)
        font.setFamily("SimSun")
        font.setItalic(True)
        self._descLbList[2].setFont(font)
        self._descLbList[2].setText("活动开始时间:" + data["activity_start_date"])
        self._descLbList[3].setFont(font)
        self._descLbList[3].setText("活动结束时间:" + data["activity_end_date"])

        # 显示销量和状态
        self._descLbList[4].setFont(font)
        text = "已参加:" + str(data["activity_signed"])
        if data["status"]:
            text += "   已发布"
        else:
            text += "   已撤销"
        self._descLbList[4].setText(text)

    def getSize(self):
        return [500, 300]

class EditWidget(QScrollArea):
    __metaclass__ = ABCMeta
    cancelBtnClicked = pyqtSignal()
    goodsStatus = pyqtSignal(list)
    goodsDelete = pyqtSignal(list)

    def __init__(self, has_status=True, parent=None):
        super(EditWidget, self).__init__(parent=parent)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        self._mainWidget = QWidget(self)
        self._btnWidget = QWidget()
        # 存储编辑过的信息
        self._data = None

        # 存放正在被编辑的商品
        self._goodsItem = None

        # 当前被按下的轮播图按键
        self._currentSlideBtn = None

        # 判断是否为添加商品初始化界面
        self._isinit = False

        # 判断是否有["status"]
        self._hasStatus = has_status

        # 上下架控制
        self._cancelBtn = QPushButton()
        self._submitBtn = QPushButton()
        self._unShelveBtn = QPushButton()
        self._cancelBtn.clicked.connect(self._onCancel)
        self._submitBtn.clicked.connect(self._onSubmit)
        self._unShelveBtn.clicked.connect(self._onUnShelve)
        self._cancelBtn.setText("取消")
        self._submitBtn.setText("发布")
        self._unShelveBtn.setText("撤销")
        # self._goodsTypeLb = QLabel()
        # self._goodsTypeLineEdit = QLineEdit()

        # 删除商品
        self._deleteBtn = QPushButton()
        self._deleteBtn.clicked.connect(self._onDelete)
        self._deleteBtn.setText("删除")

        self._cancelBtn.setProperty("class", "editWidgetBtn")
        self._submitBtn.setProperty("class", "editWidgetBtn")
        self._unShelveBtn.setProperty("class", "editWidgetBtn")
        self._deleteBtn.setProperty("class", "editWidgetBtn")

        self._initBtnWidget()
        self.setWidget(self._mainWidget)
        self.setMinimumWidth(self.width())

    def _onCancel(self):
        self.cancelBtnClicked.emit()

    def _onSubmit(self):
        self.goodsStatus.emit([True, self._isinit])

    def _onUnShelve(self):
        self.goodsStatus.emit([True, self._isinit])

    def _onDelete(self):
        if self._isinit:
            self.goodsDelete.emit([None, ])
        else:
            self.goodsDelete.emit([self._goodsItem, ])

    def _initBtnWidget(self):
        vlayout = QVBoxLayout()
        vlayout.addWidget(self._submitBtn)
        vlayout.addWidget(self._unShelveBtn)
        vlayout.addWidget(self._deleteBtn)
        vlayout.addWidget(self._cancelBtn)
        self._btnWidget.setLayout(vlayout)

    @abstractmethod
    def _initLayout(self):
        # 整体界面布局
        glayout = QGridLayout()
        glayout.addWidget(self._btnWidget)
        # glayout.setColumnStretch(0, 1)
        # glayout.setColumnStretch(1, 1)
        glayout.setContentsMargins(0, 20, 0, 0)
        self._mainWidget.setLayout(glayout)
        #self._mainWidget.resize(200, 300)

    @abstractmethod
    def _newItem(self):
        pass

    @abstractmethod
    def updateData(self, data, isinit=False):
        self._isinit = isinit
        self._data = data
        if not isinit:
            self._goodsItem = self.sender()
        else:
            self._goodsItem = None
        pass

    # 获取被编辑的数据
    @abstractmethod
    def getEditedData(self):
        pass

    # 更新对应的商品信息
    def updateGoodsItem(self):
        if not self._isinit:
            self._goodsItem.updateData(self._data)
            return None
        else:
            ret = self._newItem()
            ret.updateData(self._data)

            return ret

    # 修改上下架信息并返回
    def setSalesStatus(self, status):
        if self._hasStatus:
            if status:
                self._data["status"] = 1
                return 1
            else:
                self._data["status"] = 0
                return 0

    def currentEditItem(self):
        return self._goodsItem

class test(EditWidget):
    def __init__(self, parent=None):
        super(test, self).__init__(parent=parent)
        self._initLayout()

    def _newItem(self):
        return activityItem()

    def updateData(self, data, isinit=False):
        self._isinit = isinit
        self._data = data
        if not isinit:
            self._goodsItem = self.sender()
        else:
            self._goodsItem = None

    def getEditedData(self):
        pass

    def _initLayout(self):
        # 整体界面布局
        glayout = QGridLayout()
        glayout.addWidget(self._btnWidget)
        # glayout.setColumnStretch(0, 1)
        # glayout.setColumnStretch(1, 1)
        glayout.setContentsMargins(0, 20, 0, 0)
        self._mainWidget.setLayout(glayout)
        self._mainWidget.resize(200, 300)


class ItemDisplayWidget(QStackedWidget):
    def __init__(self, item, data, init_data, edit_widget=None, col_count=2, desc="",
                 parent=None, http=False, has_edit=True, has_add_btn=True, on_cancel_refresh_data=False):
        super(ItemDisplayWidget, self).__init__(parent)
        if has_edit:
            self._editWidget = edit_widget()
        self._itemType = item
        self._itemSize = item().getSize()   # item
        self._colCount = col_count
        self._data = data
        self._initData = init_data
        self._has_edit = has_edit
        self._has_add_btn = has_add_btn
        self._on_cancel_refresh_data = on_cancel_refresh_data
        self._mainWidget = QWidget()

        # 初始化商品列表
        self._goodsScrollArea = QScrollArea()
        self._goodsWidget = QWidget(self._goodsScrollArea)
        self._goodsList = list()
        self._glayout = QGridLayout()
        self._glayout.setSpacing(20)

        self._addGoodsItemBtn = QPushButton()
        self._addGoodsItemBtn.clicked.connect(self._addGoodsItem)
        self._addGoodsItemBtn.setProperty("class", "addBtn")
        # sd = QGraphicsDropShadowEffect()
        # sd.setColor(Qt.gray)
        # sd.setBlurRadius(45)
        # self._addGoodsItemBtn.setGraphicsEffect(sd)
        self._addGoodsItemBtn.setFixedSize(50, 50)
        self.disPlayGoodsItem(data)
        self._goodsScrollArea.setWidget(self._goodsWidget)

        self.addWidget(self._mainWidget)
        if self._has_edit:
            self.addWidget(self._editWidget)

        # 上下架及页面控制、删除商品
        if self._has_edit:
            self._editWidget.cancelBtnClicked.connect(self._onCancel)
            if http:
                self._editWidget.goodsStatus.connect(self._emit_status)
                self._editWidget.goodsDelete.connect(self._emit_del)
            else:
                self._editWidget.goodsStatus.connect(self._onStatusChange)
                self._editWidget.goodsDelete.connect(self._onDelete)

        self._descLb = QLabel()
        self._descLb.setProperty("class", "pageDescLb")
        self._descLb.setText(desc)

        self._mainWidgetLayout = QGridLayout()
        self._mainWidgetLayout.addWidget(self._descLb, 0, 0, 1, 1, Qt.AlignCenter | Qt.AlignTop)
        self._mainWidgetLayout.addWidget(self._goodsScrollArea, 1, 0, 1, 1)
        self._mainWidget.setLayout(self._mainWidgetLayout)

        if not self._has_add_btn:
            self._addGoodsItemBtn.hide()

        self.showMaximized()

    def disPlayGoodsItem(self, data, refresh=False, data_refresh=False):
        if refresh:
            for each in range(self._goodsList.__len__()):
                self._glayout.removeWidget(self._goodsList[each])
                self._goodsList[each].deleteLater()
            self._goodsList.clear()
        else:
            self._data = data

        if data_refresh:
            self._data = data

        for each in range(data.__len__()):
            self._goodsList.append(self._itemType())
            self._goodsList[each].updateData(data[each])  # item
            if self._has_edit:
                self._goodsList[each].shopItemClicked.connect(self._changeWidget)  # item

        for each in range(self._goodsList.__len__()):
            self._glayout.addWidget(self._goodsList[each], each//self._colCount+1,
                                    each%self._colCount, 1, 1, Qt.AlignTop | Qt.AlignLeft)

        self._glayout.addWidget(self._addGoodsItemBtn, 0, 0, 1, 4, Qt.AlignRight | Qt.AlignTop)
        self._goodsWidget.resize(self._colCount * self._itemSize[0] + 60,
                                 ((self._goodsList.__len__() - 1) // self._colCount + 1)
                                 * (self._itemSize[1] + 15) + 30 + self._addGoodsItemBtn.height())
        self._goodsWidget.setLayout(self._glayout)
        if not self._has_add_btn:
            self._addGoodsItemBtn.hide()

    def _reshow(self):
        self._glayout.addWidget(self._addGoodsItemBtn, 0, 0, 1, 4, Qt.AlignRight | Qt.AlignTop)
        for each in range(self._goodsList.__len__()):
            self._glayout.addWidget(self._goodsList[each], each // self._colCount + 1,
                                    each % self._colCount, 1, 1, Qt.AlignTop | Qt.AlignLeft)
        self._goodsWidget.resize(self._colCount * self._itemSize[0] + 60,
                                 ((self._goodsList.__len__() - 1) // self._colCount + 1)
                                 * (self._itemSize[1] + 15) + 30 + self._addGoodsItemBtn.height())
        if not self._has_add_btn:
            self._addGoodsItemBtn.hide()

    def _indexOfGoodsItem(self, item):
        for index in range(self._goodsList.__len__()):
            if id(item) == id(self._goodsList[index]):
                return index

        return None

    def _changeWidget(self, data):
        self.sender().setDataIndex(self._data.index(data))
        self.setCurrentIndex(1)
        self._editWidget.updateData(copy.deepcopy(data))

    def _onCancel(self):
        self.back(data_refresh=self._on_cancel_refresh_data)

    def back(self, data_refresh=False):
        if data_refresh:
            data = self._editWidget.getEditedData()
            item = self._editWidget.currentEditItem()
            item.updateData(data)
            self._data[item.dataIndex()] = data
        self.setCurrentIndex(0)

    def _onStatusChange(self, status):
        self._editWidget.setSalesStatus(status[0])
        data = self._editWidget.getEditedData()
        ret = self._editWidget.updateGoodsItem()
        if ret is not None:
            self._data.append(data)
            ret.shopItemClicked.connect(self._changeWidget)  # gai
            self._goodsList.append(ret)
            self._glayout.addWidget(ret, (self._goodsList.__len__()-1)//self._colCount+1,
                                    (self._goodsList.__len__()-1)%self._colCount,
                                    1, 1, Qt.AlignTop | Qt.AlignLeft)
            self._goodsWidget.resize(self._colCount * self._itemSize[0] + 60,
                                     ((self._goodsList.__len__() - 1) // self._colCount + 1)
                                     * (self._itemSize[1] + 15) + 30 + self._addGoodsItemBtn.height())
        else:
            item = self._editWidget.currentEditItem()
            self._data[item.dataIndex()] = data

        self.setCurrentIndex(0)

    def _addGoodsItem(self):
        self.setCurrentIndex(1)
        self._editWidget.updateData(copy.deepcopy(self._initData), True)

    def _onDelete(self, item):
        if item[0] is None:
            self.setCurrentIndex(0)
        else:
            self.setCurrentIndex(0)
            # 去除界面布局
            for each in self._goodsList:
                self._glayout.removeWidget(each)

            # 删除对应商品
            index = item[0].dataIndex()
            del self._data[index]
            goodsindex = self._goodsList.index(item[0])
            item[0].setParent(None)
            item[0].deleteLater()
            del self._goodsList[goodsindex]

            # 重新布局
            self._reshow()

    def _emit_status(self, status):
        pass

    def _emit_del(self):
        pass

    def setData(self, data):
        self._data = data

    def getData(self):
        ret = list()

        for each in self._goodsList:
            ret.append(each.getData())  # item

        return ret


class slideShowWidget(QWidget):
    def __init__(self, pic_count=3, parent=None):
        super(slideShowWidget, self).__init__(parent=parent)
        # 存放图片信息
        self._data = list()
        for index in range(pic_count):
            self._data.append("请点击插入图片")

        # 轮播图界面
        self._slideBtnWidget = QWidget()
        self._slideShowBtn = list()
        for index in range(pic_count):
            self._slideShowBtn.append(slideButton(index))
            if index == 0:
                self._currentSlideBtn = self._slideShowBtn[index]
            self._slideShowBtn[index].currentIndex.connect(self._updateSlidePic)
        self._slideShowLb = picEditableLabel()
        self._slideShowLb.setFixedSize(500, 400)
        self._initslideWdiget(pic_count)

        # 上传轮播图
        self._slideShowLb.picLbClicked.connect(self._uplaodPic)

        ret = self._displayimg(self._data[0], self._slideShowLb)
        if ret is not None:
            self._data[0] = ret

    def _initslideWdiget(self, count):
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()

        hlayout.addStretch()
        for index in range(count):
            hlayout.addWidget(self._slideShowBtn[index])
        self._slideBtnWidget.setLayout(hlayout)

        vlayout.addWidget(self._slideShowLb)
        vlayout.addWidget(self._slideBtnWidget)

        self.setLayout(vlayout)

    # 上传轮播图或图片详情图片
    def _uplaodPic(self, mode):
        fd = FileDialog(QFileDialog.AcceptOpen, "选择图片")
        path = fd.getSelectFilePath()
        if path is not None:
            img = cv2.imdecode(np.fromfile(path, dtype=np.uint8), -1)

            width = img.shape[1]
            height = img.shape[0]
            width_new = 800
            height_new = 600

            # 判断图片的长宽比率
            if width / height >= width_new / height_new:
                img_new = cv2.resize(img, (width_new, int(height * width_new / width)))
            else:
                img_new = cv2.resize(img, (int(width * height_new / height), height_new))
            # img_new = cv2.resize(img, (900, 900))

            cv2.imwrite('./temp/temp.jpg', img_new)
            with open('./temp/temp.jpg', "rb") as file:
                image_byte = b64encode(file.read())
            base64_string = image_byte.decode('utf-8')

            if mode == -1:
                index = self._currentSlideBtn.index()
                self._data[index] = base64_string
                self._updateSlidePicFromFile(index)

    # 按键切换显示图片
    def _updateSlidePic(self, index):
        self._currentSlideBtn = self.sender()
        ret = self._displayimg(self._data[index], self._slideShowLb)
        if ret is not None:
            self._data[index] = ret

    # 上传图片时显示图片
    def _updateSlidePicFromFile(self, index):
        ret = self._displayimg(self._data[index], self._slideShowLb)
        if ret is not None:
            self._data[index] = ret

    def _displayimg(self, url, label):
        pix = QPixmap()
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        if url.startswith("http"):
            QApplication.processEvents()
            response = requests.get(url)
            pix.loadFromData(response.content)
            pix = pix.scaled(label.width(), label.height())
            label.setStyleSheet("border:none")
            label.setPixmap(pix)
            image_byte = b64encode(response.content)
            base64_string = image_byte.decode('utf-8')
            QApplication.restoreOverrideCursor()
            return base64_string
        elif url == "请点击插入图片":
            label.setText(url)
            label.setStyleSheet("background-color:gray;border: 1px solid black;")
        else:
            url = url.encode("utf-8")
            image_data = b64decode(url)
            pix.loadFromData(image_data)
            pix = pix.scaled(label.width(), label.height())
            label.setStyleSheet("border:none")
            label.setPixmap(pix)
        QApplication.restoreOverrideCursor()
        return None

    def showPic(self, url):
        self._displayimg(url, self._slideShowLb)

    def getPic(self):
        return self._data

    def setPicData(self, pic):
        self._data = pic


class msgEditWidget(QWidget):
    def __init__(self, rowcount=4, date_edit_row=None, date_edit_format="yyyy-MM-dd", row_space=10, col_space=10, parent=None):
        super(msgEditWidget, self).__init__(parent=parent)
        self._rowcount = rowcount
        self._dateEditRow = date_edit_row
        self._dateEditFormat = date_edit_format
        self._rowEditList = list()
        for index in range(rowcount):
            if date_edit_row is None:
                self._rowEditList.append((QLabel(), QLineEdit()))
            else:
                if self._IndexObj(index, date_edit_row) is not None:
                    temp = QDateTimeEdit()
                    temp.setDisplayFormat(date_edit_format)
                    temp.setCalendarPopup(True)
                    temp.calendarWidget().setStyleSheet("background-color:#90EE90")
                    self._rowEditList.append((QLabel(), temp))
                else:
                    self._rowEditList.append((QLabel(), QLineEdit()))

        for each in range(self._rowEditList.__len__()):
            self._rowEditList[each][0].setObjectName("msgEditWidgetLb")

        self._layout(row_space, col_space)

    def _IndexObj(self, obj, flist):
        try:
            return flist.index(obj)
        except:
            return None

    def _layout(self, row_space, col_space):
        vlayout = QVBoxLayout()
        for index in range(self._rowcount):
            hlayout = QHBoxLayout()
            hlayout.addWidget(self._rowEditList[index][0])
            hlayout.addWidget(self._rowEditList[index][1], Qt.AlignLeft)
            vlayout.addLayout(hlayout)
            hlayout.setSpacing(col_space)
        vlayout.setSpacing(row_space)
        self.setLayout(vlayout)

    def setLabelAlign(self, align):
        for index in range(self._rowcount):
            self._rowEditList[index][0].setAlignment(align)

    def setLabelFont(self, font):
        for index in range(self._rowcount):
            self._rowEditList[index][0].setFont(font)

    def setLabelSize(self, size):
        for index in range(self._rowcount):
            self._rowEditList[index][0].setFixedSize(size[0], size[1])

    def setLineEditNumberLimit(self, row, limit, editType=int, decimal=2):
        if self._IndexObj(row, self._dateEditRow) is None:
            if editType == int:
                self._rowEditList[row][1].setValidator(QIntValidator(limit[0], limit[1]))
            elif editType == float:
                self._rowEditList[row][1].setValidator(QDoubleValidator(limit[0], limit[1], decimal))

    def getWidget(self):
        return self._rowEditList

    def getData(self):
        ret = list()

        for row in range(self._rowcount):
            if self._IndexObj(row, self._dateEditRow) is None:
                ret.append(self._rowEditList[row][1].text())
            else:
                ret.append(self._rowEditList[row][1].date().toString(self._dateEditFormat))

        return ret

    def setLabelsText(self, text):
        if text.__len__() == self._rowEditList.__len__():
            for index in range(self._rowEditList.__len__()):
                self._rowEditList[index][0].setText(text[index])
            return True
        else:
            return False

class classifyBtn(QPushButton):
    selected = pyqtSignal(str)

    def __init__(self, classname, parent=None):
        super(classifyBtn, self).__init__(parent=parent)
        self.setText(classname)
        self.setObjectName("classifyBtn")
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.clicked.connect(self._emitIndex)
        self.setFixedSize(30, 30)
        self.setCheckable(True)
        self.setAutoExclusive(True)

    def _emitIndex(self):
        self.selected.emit(self.text())

    @staticmethod
    def msize():
        return [30, 30]

class hClsWidget(QWidget):
    rowSelected = pyqtSignal(str)
    clsAdd = pyqtSignal()
    clsRm = pyqtSignal(str)

    def __init__(self, col_count=11, default_cls=[], parent=None):
        super(hClsWidget, self).__init__(parent=parent)
        self._clsBtnList = list()
        self._colCount = col_count
        self.currentChecked = None
        self._clsWidget = QWidget()

        self._glayout = QGridLayout()
        self._hlayout = QHBoxLayout()
        self._mainlayout = QHBoxLayout()

        self._btnWidget = QWidget()
        self._addBtn = QPushButton()
        self._rmBtn = QPushButton()
        self._addBtn.setObjectName("clsAddBtn")
        self._rmBtn.setObjectName("clsRmBtn")
        self._addBtn.setText("+")
        self._rmBtn.setText("-")
        self._addBtn.clicked.connect(self._onAdd)
        self._rmBtn.clicked.connect(self._onRm)
        self._initBtnWidget()

        self._initDisPlay(default_cls)
        self._initMainLayout()
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.setObjectName("hClsWidget")

    def _initBtnWidget(self):
        self._hlayout.addWidget(self._addBtn)
        self._hlayout.addWidget(self._rmBtn)
        self._hlayout.setContentsMargins(0, 0, 0, 0)
        self._btnWidget.setLayout(self._hlayout)

    def _initMainLayout(self):
        self._mainlayout.addWidget(self._clsWidget)
        self._mainlayout.addStretch()
        self._mainlayout.addWidget(self._btnWidget)
        self._mainlayout.setSpacing(0)
        self._mainlayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self._mainlayout)

    def _initDisPlay(self, cls):
        if cls.__len__() > 0:
            for each in cls:
                temp = self._addClsToList(each)
                self._addToLayout(temp)
        self._glayout.setContentsMargins(0, 0, 0, 0)
        self._clsWidget.setLayout(self._glayout)

    def _addToLayout(self, cls, pos=None):  # pos为None是追加
        if pos is None:
            self._glayout.addWidget(cls, (self._clsBtnList.__len__() - 1) // self._colCount + 1,
                                    (self._clsBtnList.__len__() - 1) % self._colCount,
                                    1, 1, Qt.AlignTop | Qt.AlignLeft)
        else:
            self._glayout.addWidget(cls, pos // self._colCount + 1,
                                    pos % self._colCount,
                                    1, 1, Qt.AlignTop | Qt.AlignLeft)

    def _addClsToList(self, classname):
        temp = classifyBtn(classname)
        temp.selected.connect(self._onSelected)
        self._clsBtnList.append(temp)
        return temp

    def addRmDisable(self):
        self._addBtn.hide()
        self._rmBtn.hide()

    def addCol(self, classname):
        temp = self._addClsToList(classname)
        self._addToLayout(temp)
        self._clsWidget.resize(self._clsWidget.width(), ((self._clsBtnList.__len__() - 1) // self._colCount + 1)
                                 * (temp.msize()[1] + 15) + 30)

    def addCols(self, classname):
        for each in classname:
            self.addCol(each)

    def _onAdd(self):
        self.clsAdd.emit()

    def addCls(self):
        text, ok = QInputDialog.getText(self, "添加分类", "类名:", QLineEdit.Normal, "")
        if ok:
            fd = FileDialog(QFileDialog.AcceptOpen, "选择" + text + "类图片")
            path = fd.getSelectFilePath()
            if path is not None:
                cls = self.hasCls(text)
                if not cls[0]:
                    if text == "":
                        WarningMessageBox("不能为空").exec()
                        self.addCls()
                    else:
                        return True, text, path
                        #self.addCol(text)
                else:
                    WarningMessageBox("此类型已存在").exec()
                    self.addCls()

        return False, None, None

    def hasCls(self, classname):
        for each in range(self._clsBtnList.__len__()):
            if classname == self._clsBtnList[each].text():
                return [True, self._clsBtnList[each], each]

        return [False, None, None]

    def delCol(self, classname):
        cls = self.hasCls(classname)
        if cls[0]:
            for each in self._clsBtnList:
                self._glayout.removeWidget(each)
            cls[1].deleteLater()
            del self._clsBtnList[cls[2]]
            self.currentChecked = None
            for each in range(self._clsBtnList.__len__()):
                self._addToLayout(self._clsBtnList[each], each)
            self._clsWidget.resize(self._clsWidget.width(), (self._clsBtnList.__len__() // self._colCount)
                                   * (classifyBtn.msize()[1] + 15) + 30)
            self.resize(self.width(), (self._clsBtnList.__len__() // self._colCount)
                                        * (classifyBtn.msize()[1] + 15) + 30)

    def _onRm(self):
        if self.currentChecked is not None:
            self.clsRm.emit(self.currentChecked.text())

    def rmCls(self):
        if self.currentChecked is not None:
            self.delCol(self.currentChecked.text())

    def _onSelected(self, text):
        self.currentChecked = self.sender()
        self.rowSelected.emit(text)

    def clsBtn(self):
        return self._clsBtnList

    def isSelected(self):
        return self.currentChecked is not None

    def current(self):
        return self.currentChecked

    def count(self):
        return self._clsBtnList.__len__()

def main():
    app = QApplication(sys.argv)
    with open("shopPjt.qss", "r") as f:
        style = f.read()
    app.setStyleSheet(style)
    #ui = classifyWidget()

    #ui.show()

    sys.exit(app.exec())

if __name__ == "__main__":
    main()
